#ifndef H_CORE_QUEUE_H
#define H_CORE_QUEUE_H
#include <iostream>

namespace QinChat{
    namespace Core{
        template <typename T>
        struct QueueNode{
            T data;
            QueueNode* next;
        };

        template <typename T>
        class Queue{
            public:
                explicit Queue(void):m_pQueueHead(nullptr), m_pQueueTail(nullptr),m_nlen(0){

                }

                ~Queue(){
                    Clear();
                }

                void Push(const T& data){
                    ++m_nlen;
                    if (IsEmpty()){
                        m_pQueueTail = nullptr;

                        m_pQueueHead = new QueueNode<T>();
                        m_pQueueHead->data = data;
                        m_pQueueHead->next = m_pQueueTail;
                    }
                    else{
                        QueueNode<T>* pCurNode = new QueueNode<T>();
                        pCurNode->data = data;
                        pCurNode->next = nullptr;
                        m_pQueueTail->next = pCurNode;
                        m_pQueueTail = pCurNode;
                    }
                }

                void Pop(void){
                    if (IsEmpty()){
                        return;
                    }

                    if (m_pQueueHead == m_pQueueTail) {
						m_pQueueTail = nullptr;
					}

                    QueueNode<T>* pCurNode = m_pQueueHead;
                    m_pQueueHead = pCurNode->next;
                    delete pCurNode;
                    --m_nlen;

                }

                bool IsEmpty(void) const{
                    return nullptr == m_pQueueHead;
                }

                int GetLength(){
                    return m_nlen;
                }

                void Clear(void){
                    while (m_pQueueHead != nullptr){
                        QueueNode<T>* pCurNode = m_pQueueHead;
                        m_pQueueHead = pCurNode->next;
                        delete pCurNode;
                    }

                    m_nlen=0;
                }

                T Front(void) const{
                    if (IsEmpty()){
                        std::cerr << "Error, queue is empty!";
                    }

                    return m_pQueueHead->data;
                }

                T& Front(void) {
                    if (IsEmpty()){
                        std::cerr << "Error, queue is empty!";
                        // return T();
                    }

                    return m_pQueueHead->data;

                }

            private:
              QueueNode<T>* m_pQueueHead;
              QueueNode<T>* m_pQueueTail;
              int m_nlen;
        };
    }
}

#endif // ! H_CORE_QUEUE_H
